package com.wsx.ones.monitor.core.exec.pull;

import com.wsx.ones.monitor.common.rpc.Status;
import com.wsx.ones.monitor.core.model.RpcRequest;
import com.wsx.ones.monitor.core.model.RpcResponse;
import com.wsx.ones.monitor.core.transport.RpcBeanException;
import org.apache.commons.lang3.reflect.MethodUtils;

import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 服务端反射操作的核心实现类
 * Created by wangshuaixin on 17/2/7.
 */
public class PullMessageHandleTask implements Callable<Boolean> {

    private RpcRequest rpcRequest;
    private RpcResponse rpcResponse;
    private ConcurrentHashMap<String, Object> rpcBeanMap;

    public PullMessageHandleTask (RpcRequest rpcRequest, RpcResponse rpcResponse, ConcurrentHashMap<String, Object> rpcBeanMap) {
        this.rpcRequest = rpcRequest;
        this.rpcResponse = rpcResponse;
        this.rpcBeanMap = rpcBeanMap;
    }


    /**
     * 线程的最终执行方法，实际操作方法
     * @return
     * @throws Exception
     */
    @Override
    public Boolean call() throws Exception {
        rpcResponse.setRequestId(rpcRequest.getRequestId());
        try {
            //根据参数采用反射机制实现方法调用
            Object result = invoke(rpcRequest);
            rpcResponse.setResultVal(result);
            rpcResponse.setStatus(Status.SUCCESS);
            return true;
        } catch (Exception e) {
            rpcResponse.setMessage(e.getMessage());
            rpcResponse.setStatus(Status.FAILE);
            return false;
        }
    }

    /**
     * 反射的实际操作，现在预留真实的实现类的结果
     * @param rpcRequest
     * @return
     * @throws Exception
     */
    private Object invoke(RpcRequest rpcRequest) throws Exception {
        //客户端传递过来的接口名称
        String inter = rpcRequest.getClassName();
        if (!rpcBeanMap.containsKey(inter)) {
            throw new RpcBeanException(inter);
        }
        //实现从初始化集合中获得该接口的实现类的实体
        Object obj = rpcBeanMap.get(inter);
        String methodName = rpcRequest.getMethodName();
        Object[] params = rpcRequest.getParametes();
        return MethodUtils.invokeExactMethod(obj, methodName, params, rpcRequest.getParameterTypes());
    }
}
